import { loadImg } from "./browser";

type OutputType = 'HTMLImageElement'|'base64'|'blob'
type DrawFn = (img_base64: HTMLImageElement, width: number, height: number, text: string) => Promise<HTMLCanvasElement>

/** 将canvas导出为base64
 * @param canvas
  * @param type 图片类型 默认为 image/png
  * @example
  const base64 = await convertCanvasToBase64(canvas, 'image/jpeg') // 'base64...'
  const base64 = await convertCanvasToBase64(canvas, 'image/webm') // 'base64...'
  */
export function convertCanvasToBase64(canvas: HTMLCanvasElement, type = 'image/png') {
  return canvas.toDataURL(type);
};

/** 将canvas转换blob
 * @param canvas 要转换的canvas元素
 * @example
 * const blob = await convertCanvasToBlob(canvas) // Blob
 */
export async function convertCanvasToBlob(canvas: HTMLCanvasElement): Promise<Blob> {
  return new Promise(resolve => canvas.toBlob(blob => resolve(blob!)));
};

/** 将canvas转换为新的图片元素
 * @param canvas 要转换的canvas元素
 * @returns 转换后的图片dom
 * @example
 * const img = await convertCanvasToImage(canvas) // <img />
 */
export async function convertCanvasToImage(canvas: HTMLCanvasElement): Promise<HTMLImageElement> {
  return new Promise(async (resolve, reject) => {
    const Blob = await convertCanvasToBlob(canvas);
    const newImg = new Image();
    const url = URL.createObjectURL(Blob);

    newImg.onload = function() {
      URL.revokeObjectURL(url);
    };
    newImg.onerror = () => {
      reject(new Error('转换图片失败'));
    };
    newImg.src = url;
    resolve(newImg);
  });
};

/** 给图片添加水印
 * @param imgFile 图片文件
 * @param watermarkText 水印文字
 * @param outputType 输出类型
 * @param drawWMFn 自定义绘制水印的函数
 * @example
 * const img = await addWatermark(file, '测试水印', 'HTMLImageElement', (img, width, height, text) => {})
 */
async function addWatermark(imgFile: File, watermarkText: string, outputType: OutputType = 'HTMLImageElement', drawWMFn: DrawFn) {
  // 检查输入的图片文件
  if (!imgFile || !imgFile.type.startsWith('image/')) {
    throw new Error('无效的图片文件');
  }


  // 使用URL.createObjectURL转换File对象为URL
  const imgURL = URL.createObjectURL(imgFile);

  // 创建img标签并加载图片，获取图片尺寸
  const tempImg: HTMLImageElement = await loadImg(imgURL);
  let width = tempImg.width;
  let height = tempImg.height;

  // 使用canvas添加水印
  const canvas = await drawWMFn(tempImg, width, height, watermarkText);

  let result = null;
  if (outputType === 'HTMLImageElement') {
    // 将canvas转换为新的图片
    result = await convertCanvasToImage(canvas);
  } else if (outputType === 'base64') {
    // 将canvas转换为base64
    result = await convertCanvasToBase64(canvas, imgFile.type);
  } else if (outputType === 'blob') {
    // 将canvas转换为blob
    result = await convertCanvasToBlob(canvas);
  }

  // 销毁之前创建的object URL
  URL.revokeObjectURL(imgURL);

  return result;
};

/** 绘制圆角矩形
 * @param ctx canvas上下文
 * @param x x轴位置
 * @param y y轴位置
 * @param width 矩形宽度
 * @param height 矩形高度
 * @param radius 圆角半径
 * @example
 * drawRoundRectPath(ctx, 0, 0, 100, 100, 20)
 */
export function drawRoundRectPath(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number) {
  ctx.beginPath();
  //从右下角顺时针绘制，弧度从0到1/2PI
  ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI / 2);
  //矩形下边线
  ctx.lineTo(radius + x, height + y);
  //左下角圆弧，弧度从1/2PI到PI
  ctx.arc(radius + x, height - radius + y, radius, Math.PI / 2, Math.PI);
  //矩形左边线
  ctx.lineTo(x, radius + y);
  //左上角圆弧，弧度从PI到3/2PI
  ctx.arc(radius + x, radius + y, radius, Math.PI, Math.PI * 3 / 2);
  //上边线
  ctx.lineTo(width - radius + x, y);
  //右上角圆弧
  ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
  //右边线
  ctx.lineTo(width + x, height - radius + y);
  ctx.closePath();
}

// 💕 以上为工具函数导出，下面作为业务函数导出
/** 使用canvas创建带有水印的图片
 * @param tempImg
 * @param width 图片宽度
 * @param height 图片高度
 * @param watermarkText 水印文字
 * @returns 带水印的canvas元素
 * @example
 * const canvas = await createWatermarkedCanvas(tempImg, width, height, watermarkText)
 */
export async function createWatermarkedCanvas(tempImg: HTMLImageElement, width: number, height: number, watermarkText: string): Promise<HTMLCanvasElement> {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');

  if (ctx) {
    ctx.drawImage(tempImg, 0, 0);

    const fontSize = 16;
    const rectH = 1.8 * fontSize;
    const rectW = (watermarkText.length + 1) * fontSize;
    const borderRadius = rectH * .2;
    const rectX = 0;
    const rectY = height - rectH;

    drawRoundRectPath(ctx, rectX, rectY, rectW, rectH, borderRadius);
    ctx.fillStyle = '#0009';
    ctx.fill();

    ctx.font = `${fontSize}px Arial`;
    ctx.fillStyle = '#fff';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(watermarkText, rectX + rectW / 2, rectY + rectH / 2);
  }

  return canvas;
};

/** 添加左下角水印
 * @param imgFile 图片文件
 * @param text 水印文字
 * @example
 * const base64 = await addLeftBottomWM(imgFile, 'moretime') // 'base64'
 */
export async function addLeftBottomWM(imgFile: File, text: string): Promise<string> {
  return await addWatermark(imgFile, text, 'base64', createWatermarkedCanvas) as string;
};
